#include "clib_container_double_linked_list.h"
#include "../../memory/allocator/clib_memory_allocator.h"


struct clib_container_double_linked_list_entry {
    //下一个元素指针
    struct clib_container_double_linked_list_entry *next;
    //上一个元素指针
    struct clib_container_double_linked_list_entry *pre;
    //当前元素数据指针
    void *data;
};

struct clib_container_double_linked_list {
    //头指针
    struct clib_container_double_linked_list_entry header;
    //当前元素个数
    size_t current_item_size;
};


struct clib_container_double_linked_list_entry *
clib_container_double_linked_list_entry_get_next(struct clib_container_double_linked_list_entry *entry) {
    clib_check_if_true_return_value(entry == NULL, NULL);
    clib_check_if_true_return_value(entry->next->data == NULL, NULL);
    return entry->next;
}

struct clib_container_double_linked_list_entry *
clib_container_double_linked_list_entry_get_pre(struct clib_container_double_linked_list_entry *entry) {
    clib_check_if_true_return_value(entry == NULL, NULL);
    clib_check_if_true_return_value(entry->pre->data == NULL, NULL);
    return entry->pre;
}

void *
clib_container_double_linked_list_entry_get_data(struct clib_container_double_linked_list_entry *entry) {
    clib_check_if_true_return_value(entry == NULL, NULL);
    return entry->data;
}


struct clib_container_double_linked_list *clib_container_double_linked_list_create() {
    //申请内存空间
    struct clib_container_double_linked_list *linked_list = clib_memory_allocator_malloc_default(
            sizeof(struct clib_container_double_linked_list));
    if (linked_list == NULL) {
        return NULL;
    }
    linked_list->current_item_size = 0;
    linked_list->header.next = &linked_list->header;
    linked_list->header.pre = &linked_list->header;
    return linked_list;
}


int
clib_container_double_linked_list_destroy(struct clib_container_double_linked_list *list) {
    clib_check_if_true_return_value(list == NULL, CLIB_RES_PARAM_ERROR);
    clib_check_if_true_return_value(list->current_item_size != 0, CLIB_RES_PARAM_ERROR);
    clib_memory_allocator_free_default(list);
    return CLIB_RES_OK;
}


size_t clib_container_double_linked_list_get_current_size(struct clib_container_double_linked_list *list) {
    clib_check_if_true_return_value(list == NULL, 0);
    return list->current_item_size;
}


struct clib_container_double_linked_list_entry *
clib_container_double_linked_list_get_first(struct clib_container_double_linked_list *list) {
    clib_check_if_true_return_value(list == NULL, NULL);
    clib_check_if_true_return_value(list->header.next == NULL, NULL);
    return list->header.next;
}


struct clib_container_double_linked_list_entry *
clib_container_double_linked_list_get_last(struct clib_container_double_linked_list *list) {
    clib_check_if_true_return_value(list == NULL, NULL);
    clib_check_if_true_return_value(list->header.pre == NULL, NULL);
    return list->header.pre;
}


static struct clib_container_double_linked_list_entry *clib_container_double_linked_list_new_entry(void *data) {
    //创建一个节点
    struct clib_container_double_linked_list_entry *new_entry = clib_memory_allocator_malloc_default(
            sizeof(struct clib_container_double_linked_list_entry));
    clib_check_if_true_return_value(new_entry == NULL, NULL);
    new_entry->data = data;
    new_entry->next = NULL;
    new_entry->pre = NULL;
    return new_entry;
}


int clib_container_double_linked_list_insert_next(struct clib_container_double_linked_list *list,
                                                  struct clib_container_double_linked_list_entry *entry,
                                                  void *data) {
    clib_check_if_true_return_value(list == NULL, CLIB_RES_PARAM_ERROR);
    clib_check_if_true_return_value(entry == NULL, CLIB_RES_PARAM_ERROR);

    struct clib_container_double_linked_list_entry *new_entry = clib_container_double_linked_list_new_entry(data);
    clib_check_if_true_return_value(new_entry == NULL, CLIB_RES_MEMORY_ERROR);
    //插入
    new_entry->next = entry->next;
    entry->next->pre = new_entry;
    entry->next = new_entry;
    new_entry->pre = entry;
    //增加元素个数
    list->current_item_size += 1;
    return CLIB_RES_OK;
}


int
clib_container_double_linked_list_insert_pre(
        struct clib_container_double_linked_list *list,
        struct clib_container_double_linked_list_entry *entry,
        void *data) {
    clib_check_if_true_return_value(list == NULL, CLIB_RES_PARAM_ERROR);
    clib_check_if_true_return_value(entry == NULL, CLIB_RES_PARAM_ERROR);

    struct clib_container_double_linked_list_entry *new_entry = clib_container_double_linked_list_new_entry(data);
    clib_check_if_true_return_value(new_entry == NULL, CLIB_RES_MEMORY_ERROR);
    struct clib_container_double_linked_list_entry *pre_entry = entry->pre;
    new_entry->next = entry;
    entry->pre = new_entry;
    pre_entry->next = new_entry;
    new_entry->pre = pre_entry;
    list->current_item_size += 1;
    return CLIB_RES_OK;
}


int clib_container_double_linked_list_insert_first(struct clib_container_double_linked_list *list,
                                                   void *data) {
    clib_check_if_true_return_value(list == NULL, CLIB_RES_PARAM_ERROR);
    return clib_container_double_linked_list_insert_next(list, &list->header, data);
}


int clib_container_double_linked_list_insert_last(struct clib_container_double_linked_list *list,
                                                  void *data) {
    clib_check_if_true_return_value(list == NULL, CLIB_RES_PARAM_ERROR);
    return clib_container_double_linked_list_insert_pre(list, &list->header, data);
}


void *clib_container_double_linked_list_delete(struct clib_container_double_linked_list *list,
                                               struct clib_container_double_linked_list_entry *entry) {
    clib_check_if_true_return_value(list == NULL, NULL);
    clib_check_if_true_return_value(entry == NULL, NULL);
    clib_check_if_true_return_value(entry->data == NULL, NULL);

    struct clib_container_double_linked_list_entry *pre_entry = entry->pre;
    struct clib_container_double_linked_list_entry *next_entry = entry->next;
    pre_entry->next = next_entry;
    next_entry->pre = pre_entry;
    void *return_data = entry->data;
    clib_memory_allocator_free_default(entry);
    //减少元素个数
    list->current_item_size -= 1;
    return return_data;
}


void *clib_container_double_linked_list_delete_first(struct clib_container_double_linked_list *list) {
    clib_check_if_true_return_value(list == NULL, NULL);
    clib_check_if_true_return_value(list->header.next == NULL, NULL);
    return clib_container_double_linked_list_delete(list, list->header.next);
}


void *clib_container_double_linked_list_delete_last(struct clib_container_double_linked_list *list) {
    clib_check_if_true_return_value(list == NULL, NULL);
    return clib_container_double_linked_list_delete(list, list->header.pre);
}


void *
clib_container_double_linked_list_replace(struct clib_container_double_linked_list *list,
                                          struct clib_container_double_linked_list_entry *entry,
                                          void *new_data) {
    clib_check_if_true_return_value(list == NULL, NULL);
    clib_check_if_true_return_value(entry == NULL, NULL);
    clib_check_if_true_return_value(entry->data == NULL, NULL);
    void *return_data = entry->data;
    entry->data = new_data;
    return return_data;
}


void *
clib_container_double_linked_list_replace_first(struct clib_container_double_linked_list *list,
                                                void *new_data) {
    return clib_container_double_linked_list_replace(list, list->header.next, new_data);
}

void *
clib_container_double_linked_list_replace_last(struct clib_container_double_linked_list *list,
                                               void *new_data) {
    return clib_container_double_linked_list_replace(list, list->header.pre, new_data);
}


struct clib_container_double_linked_list_entry *
clib_container_double_linked_list_get_entry_by_index(struct clib_container_double_linked_list *list, int index) {
    clib_check_if_true_return_value(index < 0, NULL);
    clib_check_if_true_return_value(index >= list->current_item_size, NULL);
    int find_index = 0;
    struct clib_container_double_linked_list_entry *find_entry = list->header.next;
    while (find_entry->data != NULL) {
        if (find_index == index) {
            break;
        }
        find_index += 1;
        find_entry = find_entry->next;
    }
    return find_entry;
}


void *
clib_container_double_linked_list_delete_entry_by_index(struct clib_container_double_linked_list *list, int index) {
    clib_check_if_true_return_value(index < 0, NULL);
    clib_check_if_true_return_value(index >= list->current_item_size, NULL);

    struct clib_container_double_linked_list_entry *find_entry = clib_container_double_linked_list_get_entry_by_index(
            list, index);
    clib_check_if_true_return_value(find_entry == NULL, NULL);
    return clib_container_double_linked_list_delete(list, find_entry);
}


int
clib_container_double_linked_list_moveto_next(
        struct clib_container_double_linked_list *list,
        struct clib_container_double_linked_list_entry *entry1,
        struct clib_container_double_linked_list_entry *entry2) {
    clib_check_if_true_return_value(list==NULL, CLIB_RES_PARAM_ERROR);
    clib_check_if_true_return_value(entry1 == entry2, CLIB_RES_PARAM_ERROR);
    clib_check_if_true_return_value(entry1->data == NULL, CLIB_RES_PARAM_ERROR);

    struct clib_container_double_linked_list_entry *pre_entry = entry1->pre;
    struct clib_container_double_linked_list_entry *next_entry = entry1->next;
    pre_entry->next = next_entry;
    next_entry->pre = pre_entry;

    struct clib_container_double_linked_list_entry *move_to_next_entry = entry2->next;
    entry2->next = entry1;
    entry1->pre = entry2;
    entry1->next = move_to_next_entry;
    move_to_next_entry->pre = entry1;
    return CLIB_RES_OK;
}

int
clib_container_double_linked_list_moveto_pre(
        struct clib_container_double_linked_list *list,
        struct clib_container_double_linked_list_entry *entry1,
        struct clib_container_double_linked_list_entry *entry2) {
    return clib_container_double_linked_list_moveto_next(list, entry1, entry2->pre);
}